package com.example.login.service.impl;

import com.example.login.config.JwtConfig;
import com.example.login.dto.LoginRequest;
import com.example.login.dto.LoginResponse;
import com.example.login.dto.RegisterRequest;
import com.example.login.dto.SmsLoginRequest;
import com.example.login.model.User;
import com.example.login.repository.UserRepository;
import com.example.login.service.SmsService;
import com.example.login.service.UserService;
import com.example.login.util.JwtTokenUtil;
import com.example.login.util.RedisUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Random;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private JwtConfig jwtConfig;

    @Autowired
    private SmsService smsService;

    @Value("${jwt.tokenHead}")
    private String tokenHead;

    @Value("${sms.expiration}")
    private long smsExpiration;

    @Value("${sms.length}")
    private int smsLength;

    @Override
    public User getUserByUsername(String username) {
        return userRepository.findByUsername(username).orElse(null);
    }

    @Override
    public User getUserByPhone(String phone) {
        return userRepository.findByPhone(phone).orElse(null);
    }

    @Override
    public User register(RegisterRequest registerRequest) {
        if (userRepository.existsByUsername(registerRequest.getUsername())) {
            throw new RuntimeException("用户名已被使用");
        }
        
        if (userRepository.existsByPhone(registerRequest.getPhone())) {
            throw new RuntimeException("手机号已被注册");
        }
        
        User user = new User();
        BeanUtils.copyProperties(registerRequest, user);
        
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        
        return userRepository.save(user);
    }

    @Override
    public String loginByPassword(String username, String password) {
        try {
            Authentication authentication = authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(username, password));
            
            SecurityContextHolder.getContext().setAuthentication(authentication);
            
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            return jwtConfig.generateToken(userDetails);
        } catch (BadCredentialsException e) {
            throw new BadCredentialsException("用户名或密码错误");
        }
    }

    @Override
    public String loginByCode(String phone, String code) {
        if (!smsService.verifyCode(phone, code)) {
            throw new BadCredentialsException("验证码错误或已过期");
        }
        
        Optional<User> userOpt = userRepository.findByPhone(phone);
        if (!userOpt.isPresent()) {
            return null;
        }
        
        User user = userOpt.get();
        
        UserDetails userDetails = userDetailsService.loadUserByUsername(user.getUsername());
        return jwtConfig.generateToken(userDetails);
    }

    @Override
    public boolean checkUserExists(String identifier, String type) {
        if ("username".equals(type)) {
            return userRepository.existsByUsername(identifier);
        } else if ("phone".equals(type)) {
            return userRepository.existsByPhone(identifier);
        }
        return false;
    }

    @Override
    public LoginResponse login(LoginRequest loginRequest) {
        User user = getUserByUsername(loginRequest.getUsername());
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }
        
        if (!passwordEncoder.matches(loginRequest.getPassword(), user.getPassword())) {
            throw new RuntimeException("密码错误");
        }
        
        String token = jwtTokenUtil.generateToken(user.getUsername());
        
        return buildLoginResponse(user, token);
    }

    @Override
    public LoginResponse loginBySms(SmsLoginRequest smsLoginRequest) {
        String phone = smsLoginRequest.getPhone();
        String code = smsLoginRequest.getCode();
        
        if (!smsService.verifyCode(phone, code)) {
            throw new RuntimeException("验证码错误或已过期");
        }
        
        User user = getUserByPhone(phone);
        if (user == null) {
            Map<String, Object> data = new HashMap<>();
            data.put("phone", phone);
            data.put("needRegister", true);
            
            LoginResponse response = new LoginResponse();
            response.setPhone(phone);
            response.setNeedRegister(true);
            return response;
        }
        
        UserDetails userDetails = userDetailsService.loadUserByUsername(user.getUsername());
        String token = jwtConfig.generateToken(userDetails);
        
        return buildLoginResponse(user, token);
    }

    @Override
    public boolean sendSmsCode(String phone) {
        return smsService.sendVerificationCode(phone);
    }

    @Override
    public boolean verifySmsCode(String phone, String code) {
        return smsService.verifyCode(phone, code);
    }

    private LoginResponse buildLoginResponse(User user, String token) {
        return LoginResponse.builder()
                .userId(user.getId())
                .username(user.getUsername())
                .phone(user.getPhone())
                .token(token)
                .tokenHead(tokenHead)
                .build();
    }

    private String generateSmsCode(int length) {
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            sb.append(random.nextInt(10));
        }
        return sb.toString();
    }
}